/* vim: set sw=8 ts=8 sts=8 expandtab: */
#ifndef CMAID_CONTAINER_FUNCDEF_H
#define CMAID_CONTAINER_FUNCDEF_H

#include <stdlib.h>

/**
 * @def CMAID_CONTAINER_FUNC(c)
 * @ingroup Cmaid_Container_Interface
 * Macro to access the cache interface.
 */
#define CMAID_CONTAINER_FUNC(c) ((c)->interface)

/**
 * @param c the container to retrieve the child count
 * @return Returns the number of items inside of the container
 * @brief Retrieve the memeber count of the container
 *
 * This function return the number of items inside of a container. It is
 * guaranteed to be a O(1) operation.
 */
CMAID_INLINE int 
cmaid_container_count(const Cmaid_Container *c)
{
        CMAID_CHECK_CONTAINER_RET(c, 0);
        return c->count;
}

/**
 * @param c the container to retrieve fill state
 * @return Returns @c TRUE if the container is empty else @c FALSE
 */
CMAID_INLINE int
cmaid_container_empty_is(const Cmaid_Container *c)
{
        CMAID_CHECK_CONTAINER_RET(c, 1);
        return c->count == 0;
}

/**
 * @param c the container to clear
 * @return Return no value
 * @brief Remove and free every item from the container
 *
 * This function removes every item inside of the container, if there is
 * a free function defined the item will be freed. Hence don't used items
 * after you called that function.
 */
CMAID_INLINE void
cmaid_container_clear(Cmaid_Container *c)
{
        CMAID_CHECK_CONTAINER(c);
        CMAID_CONTAINER_FUNC(c)->clear(c);
}

/**
 * @param c the container to attach the iterator
 * @param it the iterator to attach
 * @brief Attach an iterator to the container
 *
 * Attach an iterator to the given container. The iterator will point to the
 * virtual -1 item, i.e. before the very first item of the container. The
 * iterator needs to point valud memory. Don't forget to detach the iterator
 * after you used it. A normal usage case looks like this:
 *
 * @code
 * Cmaid_Iter it;
 * const char *item;
 *
 * cmaid_container_iter_attach(c, &it);
 * while ((item = cmaid_iter_next(&it)))
 *     printf("%s\n", item);
 *
 * cmaid_container_iter_detach(c, &it);
 * @endcode
 */
CMAID_INLINE void
cmaid_container_iter_attach(Cmaid_Container *c, Cmaid_Iter *it)
{
        CMAID_CHECK_CONTAINER(c);
        CMAID_CONTAINER_FUNC(c)->iter_attach(c, it);
}

/**
 * @param c the container to detach the iterator
 * @param it the iterator to detach
 * @brief Detach an iterator of the container
 *
 * This will remove the iterator from the internal iterator list. It is
 * important that you call the function after the iterator goes to be invalid,
 * i.e. after it is freed or is going to be out of scope.
 *
 */
CMAID_INLINE void
cmaid_container_iter_detach(Cmaid_Container *c, Cmaid_Iter *it)
{
        CMAID_CHECK_CONTAINER(c);
        CMAID_CONTAINER_FUNC(c)->iter_detach(c, it);
        it->container = NULL;
        it->interface = NULL;
}

/**
 * @param c the container to destroy
 * @return Returns no value
 * @brief Destroy the container and its nodes
 *
 * This will clear the container and free the memory it was using. You cannot
 * use the container after it was destroyed.
 */
CMAID_INLINE void
cmaid_container_destroy(Cmaid_Container *c)
{
        CMAID_CHECK_CONTAINER(c);
        CMAID_CONTAINER_FUNC(c)->destroy(c);
}

/**
 * @param c the container to dump
 * @param file the file to put the output in
 * @return Returns true on success
 * @brief Dumps the structure of the container
 *
 * Print the structure of the container in a dot format.
 */
CMAID_INLINE int
cmaid_container_dump(Cmaid_Container *c, FILE *file)
{
        CMAID_CHECK_CONTAINER_RET(c, FALSE);
        if (CMAID_CONTAINER_FUNC(c)->dump)
                return CMAID_CONTAINER_FUNC(c)->dump(c, file);
        return FALSE;
}

#endif /* CMAID_CONTAINER_FUNCDEF_H */
